﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Windows.Input;
using RG.Common.Configuration;
using RG.Common.Const;
using RG.Common.WPF.Commands;
using RG.Common.WPF.Dialogs;
using Microsoft.Practices.Unity;
using RG.Common;
using RG.Common.Configuration;

namespace RG.Common.WPF.Workplaces
{
    public class SettingsCollectionClass
    {
        public string Name { get; set; }
        public Guid GUid { get; set; }
    }

    [SupportDataBinding]
    public abstract class BaseFrameWorkplace : IWorkplace, IWorkplaceObject
    {
        private readonly IUnityContainer localCfg;
        public ICommand AddNewCmd { get; set; }
        public ICommand DeleteCmd { get; set; }
        
        // общее хранилище Name и GUid сеттингов всех фреймов
        [PropertySetting(SerializeAs = SettingsSerializeAs.Xml)]
        public List<SettingsCollectionClass> SettingsArray { get; set; }
        
        protected readonly IApplicationSettings presenterSettings;

        // тут храним текущий и предыдущие открытые фреймы ()
        private readonly ObservableCollection<FrameTab> tabs = new ObservableCollection<FrameTab>();
        public ObservableCollection<FrameTab> Tabs { get { return tabs; } }

        // отображение сеттингов текущего фрейма в ComboBox
        private ObservableCollection<SettingsCollectionClass> settingsArrayToShow = new ObservableCollection<SettingsCollectionClass>();
        public ObservableCollection<SettingsCollectionClass> SettingsArrayToShow
        {
            get { return settingsArrayToShow; }
            set { settingsArrayToShow = value; }
        }

        protected BaseFrameWorkplace(IUnityContainer parentCfg, IWorkplace parentWorkplace)
        {
            this.parentWorkplace = parentWorkplace;
            localCfg = parentCfg.CreateChildContainer();
            localCfg.
                RegisterInstance(localCfg).
                RegisterInstance<IWorkplace>(this);

            AddNewCmd = new DelegateCommand(DoAddNewFiltersCollection);
            DeleteCmd = new DelegateCommand<SettingsCollectionClass>(DoDeleteFiltersCollection);
            SettingsArray = new List<SettingsCollectionClass>();
            var config = new FrameConfigSettings { Id = GetType().GUID };
            presenterSettings = localCfg.Resolve<IApplicationSettings>();
            presenterSettings.Bind(config.Id.ToString(), this);
            presenterSettings.Load();
        }

        protected FrameTab selectedTab;

        // Обновление содержания ComboBox'а сеттингов (при загрузке и добавлении нового элемента)
        protected void UpdateSettingsArray(int backTo)
        {
            var list = new ObservableCollection<SettingsCollectionClass> { new SettingsCollectionClass { Name = "..." } };
            list.AddRange(new ObservableCollection<SettingsCollectionClass>(SettingsArray.Where(x => x.GUid == selectedTab.Presenter.GetType().GUID).ToList()));
            SettingsArrayToShow = list;
            CurSettingValue = SettingsArrayToShow[backTo];
        }

        // индекс выбранных сетингов текущего фрейма
        private SettingsCollectionClass curSettingValue;
        public SettingsCollectionClass CurSettingValue
        {
            get { return curSettingValue; }
            set
            {
                curSettingValue = value;
                if (value == null) return;
                var curSet = localCfg.Resolve<IApplicationSettings>();
                selectedTab.SettingsIndex = SettingsArrayToShow.IndexOf(value);
                if (value.Name != "...")
                {
                    curSet.Bind(value.GUid + value.Name, selectedTab.Presenter);
                    curSet.Load();
                    // Прибиндить сеттинг фрейма, чтобы при закрытии сохранять именно сеттинг фрейма
                    selectedTab.PresenterSettings.Bind(selectedTab.Config.Id.ToString(), selectedTab.Presenter);
                }
            }
        } 

        public void DoAddNewFiltersCollection()
        {
            var item = Cfg.Resolve<TextBoxDialogVM>();
            item.Lines = 1;
            if (!parentWorkplace.ShowEditableDialog(item, "Введите название фильтра")) return;
            var setCol = new SettingsCollectionClass
                             {
                                 Name = item.Text,
                                 GUid = (selectedTab.Presenter).GetType().GUID
                             };
            var curSet = selectedTab.PresenterSettings;
            curSet.Bind(setCol.GUid + setCol.Name, selectedTab.Presenter);
            curSet.Save();
            if (!SettingsArray.Any(x => x.GUid == setCol.GUid && x.Name == setCol.Name))
            {
                SettingsArray.Add(setCol);
                UpdateSettingsArray(SettingsArrayToShow.Count);
            }
        }

        public void DoDeleteFiltersCollection(SettingsCollectionClass curSettings)
        {
            if (curSettings == null) return;
            SettingsArray.Remove(curSettings);
            UpdateSettingsArray(0);
        }

        public IUnityContainer Cfg
        {
            get { return localCfg; }
        }
        protected IWorkplace parentWorkplace;
        public abstract void Show<TPresenter>(TPresenter presenter);
        public abstract void Close(object presenter);
        public abstract void ShowAlarm<TalarmManager>(TalarmManager frame, int id);
        public abstract void CloseAlarm();
        
        public abstract bool CanClose { get; }

        public  bool ShowDialog<TPresenter>(TPresenter presenter, string caption)
        {
            return parentWorkplace.ShowDialog(presenter, caption);
        }

        public bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption) where TEditableObject : IEditableObject
        {
            return parentWorkplace.ShowEditableDialog(presenter, caption);
        }

        public bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption, string okText, string cancelText) where TEditableObject : IEditableObject
        {
            return parentWorkplace.ShowEditableDialog(presenter, caption,okText,cancelText);
        }
        
        public void CloseDialog(bool isOk)
        {
            parentWorkplace.CloseDialog(isOk);
        }

        public void Shutdown()
        {
            parentWorkplace.Shutdown();
        }

        public void Error(string errorText)
        {
            parentWorkplace.Error(errorText);
        }

        public void Information(string infoText)
        {
            parentWorkplace.Information(infoText);
        }

        public bool? Ask(string askText)
        {
            return parentWorkplace.Ask(askText);
        }

        public bool AskYesNo(string askText)
        {
            return parentWorkplace.AskYesNo(askText);
        }

        public void PrintReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize/*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
            var vm = Cfg.Resolve<ReportPrintFrameVM>();
            vm.Name = "Загрузка...";
            vm.PrintReport<TFactory, T>(initVal, /*isPortret*/ reportPaperSize);
            vm.PrintPressedEvent += OnPrintPressed;
            Show(vm);
        }

        public string SaveReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize/*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
            var vm = Cfg.Resolve<ReportPrintFrameVM>();
            return vm.SaveReport<TFactory, T>(initVal, /*isPortret*/ reportPaperSize);
        }

       
        public string SelfScreen()
        {
            return parentWorkplace.SelfScreen();
        }

        public event EventHandler ReportPrintPressed;

        private void OnPrintPressed(object sender, EventArgs e)
        {
            if (ReportPrintPressed != null)
            {
                ReportPrintPressed(sender, e);
            }
        }

        public void PrintReportFromFile(string path,string name)
        {
            var vm = Cfg.Resolve<ReportPrintFrameVM>();
            vm.Name = name;
            vm.PrintReportFromFile(path);
            Show(vm);
        }
    }
}
